package com.jl.js.core;

import java.util.ArrayList;

import org.mozilla.javascript.Context;
import org.mozilla.javascript.Function;
import org.mozilla.javascript.NativeArray;
import org.mozilla.javascript.Scriptable;
import org.mozilla.javascript.ScriptableObject;
import org.mozilla.javascript.annotations.JSFunction;
import org.mozilla.javascript.annotations.JSGetter;

public class JSArrayList extends ScriptableObject {

	private ArrayList<Object> innerList = new ArrayList<Object>();

	public JSArrayList() {
	}

	public static Scriptable jsConstructor(Context ctx, Object[] args,
			Function ctorObj, boolean inNewExpr) throws Exception {

		if (!inNewExpr) {
			Context.reportError("ArrayList() can not be called as function");
		}
		JSArrayList list = new JSArrayList();
		for (Object obj : args) {
			if (obj instanceof NativeArray) {
				NativeArray array = (NativeArray) obj;
				for (int i = 0; i < array.getLength(); i++) {
					list.getInnerList().add(array.get(i));
				}
			} else if (obj instanceof Object[]) {
				for (Object one : (Object[]) obj) {
					list.getInnerList().add(one);
				}
			} else {
				list.getInnerList().add(obj);
			}
		}
		return list;
	}

	public JSArrayList(ArrayList<Object> objs) {
		this.innerList.addAll(objs);
	}

	@Override
	public String getClassName() {
		return "ArrayList";
	}

	@JSFunction
	public boolean add(Object e) {
		return innerList.add(e);
	}

	@JSFunction("addByIndex")
	public void add(int index, Object element) {
		innerList.add(index, element);
	}

	@JSFunction
	public boolean addAll(JSArrayList c) {
		return innerList.addAll(c.getInnerList());
	}

	@JSFunction("addAllByIndex")
	public boolean addAll(int index, JSArrayList c) {
		return innerList.addAll(index, c.getInnerList());
	}

	@JSFunction
	public void clear() {
		innerList.clear();
	}

	@Override
	@JSFunction
	public boolean isEmpty() {
		return innerList.isEmpty();
	}

	@JSFunction
	public boolean contains(Object o) {
		return innerList.contains(o);
	}

	@JSFunction
	public boolean containsAll(JSArrayList c) {
		return innerList.containsAll(c.getInnerList());
	}

	@JSFunction
	public Object get(int index) {
		return innerList.get(index);
	}

	@JSFunction
	public int indexOf(Object o) {
		return innerList.indexOf(o);
	}

	@JSFunction
	public int lastIndexOf(Object o) {
		return innerList.lastIndexOf(o);
	}

	@JSFunction
	public boolean remove(Object o) {
		return innerList.remove(o);
	}

	@JSFunction("removeByIndex")
	public Object remove(int index) {
		return innerList.remove(index);
	}

	@JSFunction
	public boolean removeAll(JSArrayList c) {
		return innerList.removeAll(c.getInnerList());
	}

	@JSFunction
	public Object set(int index, Object element) {
		return innerList.set(index, element);
	}

	@Override
	@JSGetter
	public int size() {
		return innerList.size();
	}

	@JSFunction
	public Scriptable subList(int fromIndex, int toIndex) {
		Context cx = Context.getCurrentContext();
		Scriptable parent = ScriptableObject.getTopLevelScope(this);
		Object[] objs = innerList.subList(fromIndex, toIndex).toArray();
		return cx.newObject(parent, "ArrayList", new Object[] { objs });
	}

	@JSFunction
	public Object[] toArray() {
		Object[] obj = innerList.toArray();
		return obj;
	}

	private ArrayList<Object> getInnerList() {
		return innerList;
	}

}
